package com.cn.algorithm.one.tree;


import com.cn.algorithm.one.printer.BinaryTrees;

import java.util.Comparator;

public class BST<E> extends BinaryTree<E> {

    Comparator<E> comparator;

    public BST(Comparator<E> comparator) {
        this.comparator = comparator;
    }

    public BST() {
        this(null);
    }

    public void put(E element) {
        if (root == null) {
            root = createNode(element, null);
            size++;
            afterPut(root);
            return;
        }
        Node<E> node = root;
        int cmp = -1;
        Node<E> parent = null;
        do {
            parent = node;
            cmp = compare(element, node.element);
            if (cmp > 0) {
                node = node.right;
            } else if (cmp < 0) {
                node = node.left;
            } else {
                return;
            }
        } while (node != null);
        Node<E> newNode = createNode(element, parent);
        if (cmp > 0) {
            parent.right = newNode;
        } else {
            parent.left = newNode;
        }
        afterPut(newNode);
        size++;
    }

    public void afterPut(Node<E> node) {

    }

    public boolean remove(E element) {
        Node<E> node = node(element);
        if (node == null) {
            return false;
        }
        if (node.hasTwoChildren()) {
            Node<E> successor = successor(node);
            node.element = successor.element;
            node = successor;
        }
        Node<E> replaceNode = node.left == null ? node.right : node.left;
        if (replaceNode != null) {
            replaceNode.parent = node.parent;
            if (node.parent == null) {
                root = replaceNode;
            } else if (node.isLeftChild()) {
                node.parent.left = replaceNode;
            } else {
                node.parent.right = replaceNode;
            }
            afterRemove(replaceNode);
        } else if (node.parent == null) {
            root = null;
            afterRemove(node);
        } else {
            if (node.isLeftChild()) {
                node.parent.left = null;
            } else {
                node.parent.right = null;
            }
            afterRemove(node);
        }
        size--;
        return true;
    }

    public void afterRemove(Node<E> node) {

    }

    public boolean contains(E element) {
        return node(element) != null;
    }

    public Node<E> createNode(E element, Node<E> parent) {
        return new Node<>(element, parent);
    }

    public Node<E> node(E element) {
        Node<E> node = root;
        int cmp = -1;
        while (node != null) {
            cmp = compare(element, node.element);
            if (cmp == 0) {
                return node;
            } else if (cmp > 0) {
                node = node.right;
            } else {
                node = node.left;
            }
        }
        return null;
    }


    public int compare(E e1, E e2) {
        return comparator == null ? ((Comparable<E>) e1).compareTo(e2) : comparator.compare(e1, e2);
    }


    public static void main(String[] args) {
        Integer data[] = new Integer[] {
                // 7, 4
                // 7, 4, 9
                // 7, 4, 9, 5
                // 7, 4, 9, 2
                // 7, 4, 9, 2, 8
                7, 4, 8, 9, 10,  2, 3, 1
        };

        AVL<Integer> bst = new AVL<>();
        for (int i = 0; i < data.length; i++) {
            bst.put(data[i]);
        }

        BinaryTrees.println(bst);
        System.out.println(bst.contains(4));
        System.out.println("----------------------------------");
        System.out.println(bst.isCompleteTree());
        bst.remove(1);
        BinaryTrees.println(bst);
        System.out.println(bst.isCompleteTree());
    }
}
